package com.example.calculators

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.core.text.isDigitsOnly
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.math.*

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private val currentInputNumSB = StringBuilder()
    private var isNumStart = true

    private val input = mutableListOf<String>()
    private val rePolish = mutableListOf<String>()
    private val output = mutableListOf<Float>()

    //双目运算符
    private val operatorList: Array<String> = arrayOf("+", "-", "x", "÷", "^", "%")
    //计算机显示的单目运算符
    private val singleOperationList: Array<String> =
        arrayOf("sin", "cos", "tan", "ln", "log2(", "log10(", "√")
    //原始单目运算符
    private val realSingleOpList:Array<String> =
        arrayOf("sin", "cos", "tan", "ln", "log2", "log10", "√￣")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //等于按钮
        textView21.setOnClickListener {
            calculateButtonClicked(it)
        }

        //清空按钮
        textView26.setOnClickListener {
            clearButtonClicked(it)
        }
        //返回按钮
        imageView.setOnClickListener {
            backButtonClicked(it)
        }
        //乘法
        textView2.setOnClickListener {
            operatorButtonClicked(it)
        }
        //除法
        textView18.setOnClickListener {
            operatorButtonClicked(it)
        }
        //加法
        textView19.setOnClickListener {
            operatorButtonClicked(it)
        }
        //减法
        textView20.setOnClickListener {
            operatorButtonClicked(it)
        }
        //左括号
        textView4.setOnClickListener {
            operatorButtonClicked(it)
        }
        //右括号
        textView5.setOnClickListener {
            operatorButtonClicked(it)
        }
        //sin
        textView97.setOnClickListener {
            operatorButtonClicked(it)
        }
        //cos
        textView25.setOnClickListener {
            operatorButtonClicked(it)
        }
        //幂运算
        textView23.setOnClickListener {
            operatorButtonClicked(it)
        }
        //求余
        textView24.setOnClickListener {
            operatorButtonClicked(it)
        }
        //ln
        textView27.setOnClickListener {
            operatorButtonClicked(it)
        }
        //log2
        textView3.setOnClickListener {
            operatorButtonClicked(it)
        }
        //log10
        textView29.setOnClickListener {
            operatorButtonClicked(it)
        }
        //平方根
        textView30.setOnClickListener {
            operatorButtonClicked(it)
        }
        textView31.setOnClickListener {
            operatorButtonClicked(it)
        }

        //绑定数字
        textView6.setOnClickListener(this)
        textView7.setOnClickListener(this)
        textView10.setOnClickListener(this)
        textView11.setOnClickListener(this)
        textView8.setOnClickListener(this)
        textView12.setOnClickListener(this)
        textView13.setOnClickListener(this)
        textView9.setOnClickListener(this)
        textView14.setOnClickListener(this)
        textView15.setOnClickListener(this)
        textView16.setOnClickListener(this)
        textView17.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        numberButtonClicked(v!!)
    }

    //数字键
    private fun numberButtonClicked(view: View) {
        //将view强制转化为TextView
        val tv = view as TextView

        if (tv.text.toString() == "-/+")
            currentInputNumSB.append("-")
        else
            currentInputNumSB.append(tv.text)
        if (isNumStart) {
            //当前输入的是一个新的数字 ，添加到数组中
            if (tv.text.toString() == "-/+")
                input.add("-")
            else
                input.add(tv.text.toString())
            //更改状态 已经不是一个新数字的开始了
            isNumStart = false
        } else {
            //用当前的数字去替换数组中最后一个元素
            if (tv.text.toString() == "-/+")
                return
            input[input.size - 1] = currentInputNumSB.toString()
        }

        //显示内容
        showUI()
    }

    //运算符键
    fun operatorButtonClicked(view: View) {

        //将view强制转化为TextView
        val tv = view as TextView
        val op = tv.text.toString()

        if (op in realSingleOpList) {
            if (input.isNotEmpty())
                if (isDigits(input.last())|| input.last()==")")
                    input.add("x")
        }

        if (op == "log2")
            input.add("log2(")
        else if (op == "log10")
            input.add("log10(")
        else if (op == "√￣")
            input.add("√")
        else
        //保存当前运算符
            input.add(tv.text.toString())
        //改变状态
        isNumStart = true
        currentInputNumSB.clear()
        //显示内容
        showUI()
    }

    //清空键
    private fun clearButtonClicked(view: View) {
        process_textview.text = ""
        result_textview.text = "0"
        currentInputNumSB.clear()
        input.clear()
        rePolish.clear()
        output.clear()
        isNumStart = true
    }

    //撤销
    private fun backButtonClicked(view: View) {

        if (input.isNotEmpty()) {
            input.removeLast()
            if (input.isNotEmpty()) {
                isNumStart = !isDigits(input.last())
            } else{
                isNumStart =true
            }
        }
        currentInputNumSB.clear()
        showUI()
    }

    //拼接当前运算的表达式 显示到界面上
    private fun showUI() {
        val str = StringBuilder()
        for ((i, num) in input.withIndex()) {
            //将当前的数字拼接上去
            str.append(num)
        }
        process_textview.text = str.toString()
    }

    //计算结果
    private fun calculateButtonClicked(view: View) {
        if (input.isEmpty())
            return
        showUI()
        try {
            rePolish()
            calculate()
        } catch (e: Exception) {
            input.clear()
            rePolish.clear()
            output.clear()
            process_textview.text = "0"
            result_textview.text = "格式错误!"
            e.printStackTrace()
        }
    }

    //中缀表达式变成逆波兰式
    private fun rePolish() {
        //临时栈，存放操作符
        val stack = mutableListOf<String>()
        rePolish.clear()
        for (str in input) {
            println("str is $str")
            //1.如果是数字 压入s1
            if (isDigits(str)) {
                rePolish.add(str)
            }
            //2.如果遇到的是左括号，将左括号压入S2中；
            if (str == "(") {
                stack.add(str)
            }
            //3.如果遇到的是右括号
            if (str == ")") {
                //将S2中的运算符一直出栈压入S1中，直到遇到左括号，但是该左括号出S2却不入S1
                while (stack.last() != "(") {
                    rePolish.add(stack.removeLast())

                }
                if (stack.last() == "(") {
                    stack.removeLast()
                }
            }
            //4.如果遇到的是运算符，按照如下规则操作：
            if (isOp(str)) {
                //（1）如果S2为空，将运算符压入S2中
                if (stack.isEmpty()) {
                    stack.add(str)
                }
                //（2）如果S2不为空，当前遍历到的运算符优先级不小于S2栈顶运算符，将当前遍历到的运算符压入S2；
                else if (priority(str) >= priority(stack.last())) {
                    stack.add(str)
                }
                //（3）如果S2不为空，当前遍历到的运算符优先级小于S2栈顶运算符，
                // 将栈顶运算符一直出栈压入S1中，直到栈为空或遇到一个运算符优先 级小于当前遍历到的运算符，
                // 此时将当前遍历到的运算符压入S2；
                else if (priority(str) < priority(stack.last())) {
                    while (priority(str) <= priority(stack.last())) {
                        rePolish.add(stack.removeLast())
                        if (stack.isEmpty())
                            break
                    }
                    stack.add(str)
                }
            }
        }
        while (stack.isNotEmpty()) {
            rePolish.add(stack.removeLast())
        }
    }

    //计算后缀
    private fun calculate() {
        output.clear()
        for (str in rePolish) {
            //1.如果是数字，压入output
            if (isDigits(str)) {
                output.add(str.toFloat())
            }
            if (isOp(str)) {
                //2.如果遇到双目运算符，取S3栈顶两个元素（先出栈的在右，后出栈的在左）进行 双目运算，将结果再次压入output中
                if (!isSingleOp(str)) {
                    val p1 = output.removeLast()
                    val p2 = output.removeLast()
                    output.add(realCalculate(p2, str, p1))
                }
                //2.如果遇到单目运算符，取S3栈顶一个元素进行 单目运算，将结果再次压入output中
                else {
                    val p1 = output.removeLast()
                    output.add(realCalculate(p1, str, p1))
                }
            }
        }
        result_textview.text = String.format("%.3f", output.last())
    }

    //操作符优先级
    private fun priority(op: String): Int {
        if (op == "+" || op == "-")
            return 1
        if (op == "x" || op == "÷")
            return 2
        if (op == "^" || op == "%")
            return 3
        if (op in singleOperationList)
            return 4
        else
            return 0
    }

    //判断是否为操作符
    private fun isOp(str: String): Boolean {
        for (op in operatorList) {
            if (str == op)
                return true
        }
        for (op in singleOperationList)
            if (str == op)
                return true
        return false
    }

    //判断是否为单目运算符
    private fun isSingleOp(str: String): Boolean {
        for (op in singleOperationList)
            if (str == op)
                return true
        return false
    }

    //判断是否为数字
    private fun isDigits(str: String): Boolean {
        if (str != "(" && str != ")") {
            if (isOp(str))
                return false
            return true
        } else {
            return false
        }
    }

    // 运算
    private fun realCalculate(param1: Float, operator: String, param2: Float): Float {
        var result = 0.0f
        when (operator) {
            "+" -> {
                result = param1 + param2
            }
            "-" -> {
                result = param1 - param2
            }
            "x" -> {
                result = param1 * param2
            }
            "÷" -> {
                result = param1 / param2
            }
            "^" -> {
                result = param1.toDouble().pow(param2.toDouble()).toFloat()
            }
            "sin" -> {
                result = sin(param1)
            }
            "cos" -> {
                result = cos(param1)
            }
            "%" -> {
                result = param1.rem(param2)
            }
            "ln" -> {
                result = ln(param1)
            }
            "tan" -> {
                result = tan(param1)
            }
            "log2(" -> {
                result = log2(param1)
            }
            "log10(" -> {
                result = log10(param1)
            }
            "√" -> {
                result = sqrt(param1)
            }

        }
        return result
    }
}